home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xmbase-grok-1.2 / util.c < prev   
C/C++ Source or Header  |  1995-06-25  |  13KB  |  540 lines

  1. /*
  2.  * Initializes everything and starts a calendar window for the current
  3.  * month. The interval timer (for autosave and entry recycling) and a
  4.  * few routines used by everyone are also here.
  5.  *
  6.  *    section_name(db,n)        return name of section nsect
  7.  *    resolve_tilde(path)        return path with ~ replaced with home
  8.  *                    directory as found in $HOME
  9.  *    find_file(buf, name,exec)    find file <name> and store the path
  10.  *                    in <buf>. Return FALSE if not found.
  11.  *    fatal(char *fmt, ...)        Prints an error message and exits.
  12.  *    print_button(w, fmt, ...)    Prints a string into a string Label
  13.  *                    or PushButton. %s may not be NULL.
  14.  *    print_text_button(w, fmt, ...)    Prints a string into a Text button.
  15.  *                    %s may not be NULL.
  16.  *    print_text_button_s(w, str)    Prints a string, str may be NULL
  17.  *    set_icon(shell, sub)        changes the icon pixmap of a window
  18.  *    truncate_string(str,len,sfont)    truncate string to fit into <len>
  19.  *    strlen_in_pixels(str, sfont)    return length of string in pixels
  20.  *
  21.  *    to_octal(n)            convert ascii to octal string
  22.  *    to_ascii(str, def)        convert octal string to ascii
  23.  */
  24.  
  25. #include "config.h"
  26. #include <X11/Xos.h>
  27. #include <stdarg.h>
  28. #include <stdlib.h>
  29. #include <pwd.h>
  30. #include <signal.h>
  31. #include <Xm/Xm.h>
  32. #include <Xm/Text.h>
  33. #include <X11/StringDefs.h>
  34. #include <X11/cursorfont.h>
  35. #include "grok.h"
  36. #include "form.h"
  37. #include "proto.h"
  38. #include "patchlevel.h"
  39. #include "bm_icon.h"
  40.  
  41. extern Display        *display;    /* everybody uses the same server */
  42. extern GC        gc;        /* everybody uses this context */
  43. extern Widget        toplevel;    /* top-level shell for icon name */
  44. extern struct config    config;        /* global configuration data */
  45. extern XFontStruct    *font[NFONTS];    /* fonts: FONT_* */
  46. extern Pixel        color[NCOLS];    /* colors: COL_* */
  47. extern char        *progname;    /* argv[0] */
  48.  
  49.  
  50.  
  51. /*
  52.  * extract a section name from the section paths by removing the extension
  53.  * and common substrings.
  54.  */
  55.  
  56. char *section_name(
  57.     register DBASE     *dbase,        /* contains section array */
  58.     int         n)            /* 0 .. dbase->nsects-1 */
  59. {
  60.     static char     name[40];        /* returned name */
  61.     register SECTION *sect;            /* section list */
  62.     register char     *path;            /* path to reduce */
  63.     register char     *trunc;        /* trailing unique part */
  64.     register int     i;            /* section counter */
  65.  
  66.     if (!dbase || n < 0 || n >= dbase->nsects)
  67.         return("");
  68.     sect = dbase->sect;
  69.     path = sect[n].path;
  70.     if (!path || !*path)
  71.         return("");
  72.     trunc = strrchr(sect[n].path, '/');
  73.     while (trunc > path) {
  74.         for (i=dbase->nsects-1; i >= 0; i--)
  75.             if (i != n && strncmp(path, sect[i].path, trunc-path))
  76.                 break;
  77.         if (i < 0)
  78.             break;
  79.         while (trunc > path && *trunc != '/')
  80.             trunc--;
  81.     }
  82.     if (!trunc)
  83.         trunc = path;
  84.     else if (*trunc == '/')
  85.         trunc++;
  86.     i = strlen(trunc);
  87.     if (i > sizeof(name)-1)
  88.         sprintf(name, "...%s", trunc + i - (sizeof(name)-4));
  89.     else
  90.         strcpy(name, trunc);
  91.     if ((trunc = strrchr(name, '.')) && trunc > strrchr(name , '/'))
  92.         *trunc = 0;
  93.     return(name);
  94. }
  95.  
  96.  
  97. /*
  98.  * If <path> begins with a tilde, replace the tilde with $HOME. This is used
  99.  * for the database files, and the holiday file (see holiday.c). If the path
  100.  * is relative (ie., does not begin with ~ or !) and does not begin with "./",
  101.  * prepend GROKDIR and append ext. This is the default, all files are normally
  102.  * in ~/.grok. Also strip unnecessary leading and trailing / and /. to prevent
  103.  * forms from appearing multiple times in the database pulldown.
  104.  */
  105.  
  106. char *resolve_tilde(
  107.     char        *path,            /* path with ~ */
  108.     char        *ext)            /* append extension unless 0 */
  109. {
  110.     struct passwd    *pw;            /* for searching home dirs */
  111.     static char    pathbuf[1024];        /* path with ~ expanded */
  112.     char        buf[1024];        /* buf for prepending GROKDIR*/
  113.     char        *p, *q;            /* username copy pointers */
  114.     char        *home = 0;        /* home dir (if ~ in path) */
  115.     int        i;            /* strip trailing / and /. */
  116.  
  117.     if (*path != '~' && *path != '/' && (*path != '.' || path[1] != '/')) {
  118.         sprintf(buf, "%s/%s", GROKDIR, path);
  119.         path = buf;
  120.         if (ext) {
  121.             if ((p = strrchr(path, '.')) && !strcmp(p+1, ext))
  122.                 *p = 0;
  123.             strcat(path, ".");
  124.             strcat(path, ext);
  125.         }
  126.     }
  127.     if (*path == '~') {
  128.         if (!path[1] || path[1] == '/') {
  129.             *pathbuf = 0;
  130.             if (!(home = getenv("HOME")))
  131.                 home = getenv("home");
  132.             path += 2;
  133.         } else {
  134.             for (path++,q=pathbuf; *path && *path!='/'; path++,q++)
  135.                 *q = *path;
  136.             path++;
  137.             *q = 0;
  138.             if (pw = getpwnam(pathbuf))
  139.                 home = pw->pw_dir;
  140.         }
  141.         if (!home) {
  142.             fprintf(stderr,
  143.                 "%s: can't evaluate ~%s in %s, using .\n",
  144.                         progname, pathbuf, path);
  145.             home = ".";
  146.         }
  147.         sprintf(pathbuf, "%s/%s", home, path);
  148.         path = pathbuf;
  149.     }
  150.     for (i=strlen(path)-1; i > 0; )
  151.         if (path[i] == '/' || path[i] == '.' && path[i-1] == '/')
  152.             path[i--] = 0;
  153.         else
  154.             break;
  155.     return(path);
  156. }
  157.  
  158.  
  159. /*
  160.  * locate a program or file, and return its complete path. This is used by
  161.  * the daemon to locate notifier and user programs, and by grok to locate
  162.  * grok.hlp. Assume that <buf> has space for 1024 chars. PATH is a macro
  163.  * defined by the Makefile.
  164.  */
  165.  
  166. #ifndef PATH
  167. #define PATH 0
  168. #endif
  169. #define DEFAULTPATH "/usr/local/bin:/usr/local/lib:/bin:/usr/bin:/usr/sbin:/usr/ucb:/usr/bsd:/usr/bin/X11:."
  170.  
  171. BOOL find_file(
  172.     char            *buf,        /* buffer for returned path */
  173.     char            *name,        /* file name to locate */
  174.     BOOL            exec)        /* must be executable? */
  175. {
  176.     int            method;        /* search path counter */
  177.     char            *path;        /* $PATH or DEFAULTPATH */
  178.     int            namelen;    /* len of tail of name */
  179.     register char        *p, *q;        /* string copy pointers */
  180.  
  181.     if (*name == '/') {                /* begins with / */
  182.         strcpy(buf, name);
  183.         return(TRUE);
  184.     }
  185.     if (*name == '~') {                 /* begins with ~ */
  186.         strcpy(buf, resolve_tilde(name, 0));
  187.         return(TRUE);
  188.     }
  189.     namelen = strlen(name);
  190.     for (method=0; ; method++) {    
  191.         switch(method) {
  192.           case 0:   path = PATH;        break;
  193.           case 1:   path = getenv("GROK_PATH");    break;
  194.           case 2:   path = getenv("PATH");    break;
  195.           case 3:   path = DEFAULTPATH;        break;
  196.           default:  return(FALSE);
  197.         }
  198.         if (!path)
  199.             continue;
  200.         do {
  201.             q = buf;
  202.             p = path;
  203.             while (*p && *p != ':' && q < buf + 1021 - namelen)
  204.                 *q++ = *p++;
  205.             *q++ = '/';
  206.             strcpy(q, name);
  207.             if (!access(buf, exec ? X_OK : R_OK))
  208.                 return(TRUE);
  209.             *buf = 0;
  210.             path = p+1;
  211.         } while (*p);
  212.     }
  213.     return(FALSE); /* for lint */
  214. }
  215.  
  216.  
  217. /*
  218.  * whenever something goes seriously wrong, this routine is called. It makes
  219.  * code easier to read. fatal() never returns.
  220.  */
  221.  
  222. /*VARARGS*/
  223. void fatal(char *fmt, ...)
  224. {
  225.     va_list            parm;
  226.  
  227.     va_start(parm, fmt);
  228.     fprintf(stderr, "%s: ", progname);
  229.     vfprintf(stderr, fmt, parm);
  230.     va_end(parm);
  231.     putc('\n', stderr);
  232.     exit(1);
  233. }
  234.  
  235.  
  236. /*
  237.  * Ultrix doesn't have strdup, so we'll need to define one locally.
  238.  */
  239.  
  240. char *mystrdup(
  241.     register char *s)
  242. {
  243.     register char *p = NULL;
  244.  
  245.     if (s && (p = (char *)malloc(strlen(s)+1)))
  246.         strcpy(p, s);
  247.     return(p);
  248. }
  249.  
  250.  
  251. /*
  252.  * some systems use mybzero (BSD), others memset (SysV), I'll roll my own...
  253.  */
  254.  
  255. void mybzero(
  256.     void        *p,
  257.     register int    n)
  258. {
  259.     register char    *q = p;
  260.     while (n--) *q++ = 0;
  261. }
  262.  
  263.  
  264. /*
  265.  * Sinix doesn't have strcasecmp, so here is my own. Not as efficient as
  266.  * the canonical implementation, but short, and it's not time-critical.
  267.  */
  268.  
  269. int mystrcasecmp(
  270.     register char *a,
  271.     register char *b)
  272. {
  273.     register char ac, bc;
  274.  
  275.     while ((ac = *a++) && (bc = *b++)) {
  276.         if (ac <= 'Z' && ac >= 'A')    ac += 'a' - 'A';
  277.         if (bc <= 'Z' && bc >= 'A')    bc += 'a' - 'A';
  278.         if (ac != bc)
  279.             break;
  280.     }
  281.     return(ac - bc);
  282. }
  283.  
  284.  
  285. /*---------------------------------------------------------------------------*/
  286. /*
  287.  * draw some text into a button. This is here because it's used by many
  288.  * routines.
  289.  */
  290.  
  291. void print_button(Widget w, char *fmt, ...)
  292. {
  293.     va_list            parm;
  294.     Arg            args;
  295.     XmString        string;
  296.     char            buf[1024];
  297.  
  298.     if (w) {
  299.         va_start(parm, fmt);
  300.         if (!fmt) fmt = "";
  301.         vsprintf(buf, fmt, parm);
  302.         va_end(parm);
  303.         string = XmStringCreateSimple(buf);
  304.         XtSetArg(args, XmNlabelString, string);
  305.         XtSetValues(w, &args, 1);
  306.         XmStringFree(string);
  307.     }
  308. }
  309.  
  310. void print_text_button(Widget w, char *fmt, ...)
  311. {
  312.     va_list            parm;
  313.     XmString        string;
  314.     char            buf[1024];
  315.  
  316.     if (w) {
  317.         va_start(parm, fmt);
  318.         if (!fmt) fmt = "";
  319.         vsprintf(buf, fmt, parm);
  320.         va_end(parm);
  321.         string = XmStringCreateSimple(buf);
  322.         XmTextSetString(w, buf);
  323.         XmTextSetInsertionPosition(w, strlen(buf));
  324.         XmStringFree(string);
  325.     }
  326. }
  327.  
  328. void print_text_button_s(Widget w, char *str)
  329. {
  330.     XmString        string;
  331.  
  332.     if (!w)
  333.         return;
  334.     if (!str)
  335.         str = "";
  336.     string = XmStringCreateSimple(str);
  337.     XmTextSetString(w, str);
  338.     XmTextSetInsertionPosition(w, strlen(str));
  339.     XmStringFree(string);
  340. }
  341.  
  342.  
  343. /*
  344.  * turn radio button on or off
  345.  */
  346.  
  347. void set_toggle(
  348.     Widget            w,
  349.     BOOL            set)
  350. {
  351.     Arg            arg;
  352.  
  353.     if (w) {
  354.         XtSetArg(arg, XmNset, set);
  355.         XtSetValues(w, &arg, 1);
  356.     }
  357. }
  358.  
  359.  
  360. /*
  361.  * return the text string in a text button. If ptr==0, return a static
  362.  * buffer containing the text; else assume that ptr points to a strdup'ed
  363.  * pointer. Free it if nonzero, then strdup the new text.
  364.  */
  365.  
  366. static char *readbutton(
  367.     Widget            w,
  368.     char            **ptr,
  369.     BOOL            skipblank,
  370.     BOOL            noblanks)
  371. {
  372.     char            *string, *s;    /* contents of text widget */
  373.     static char        *buf;
  374.     static int        bufsize;
  375.     int            size;
  376.  
  377.     if (w) {
  378.         s = string = XmTextGetString(w);
  379.         if (skipblank) {
  380.             while (*s == ' ' || *s == '\t')
  381.                 s++;
  382.             if (noblanks)
  383.                 for (size=0; s[size]; size++)
  384.                     if (s[size] == ' ' || s[size] == '\t')
  385.                         s[size] = '_';
  386.             size = strlen(s);
  387.             while (size && (s[size-1] == ' ' || s[size-1] == '\t'))
  388.                 size--;
  389.             s[size++] = 0;
  390.         } else
  391.             size = strlen(s) + 1;
  392.  
  393.         if (size > bufsize) {
  394.             if (buf) free(buf);
  395.             if (!(buf = malloc(bufsize = size)))
  396.                 return(0);
  397.         }
  398.         strcpy(buf, s);
  399.         XtFree(string);
  400.     } else if (buf)
  401.         *buf = 0;
  402.     if (ptr) {
  403.         if (*ptr) free(*ptr);
  404.         *ptr = buf && *buf ? mystrdup(buf) : 0;
  405.     }
  406.     return(buf);
  407. }
  408.  
  409. char *read_text_button_noskipblank(Widget w, char **ptr)
  410.     { return(readbutton(w, ptr, FALSE, FALSE)); }
  411.  
  412. char *read_text_button(Widget w, char **ptr)
  413.     { return(readbutton(w, ptr, TRUE, FALSE)); }
  414.  
  415. char *read_text_button_noblanks(Widget w, char **ptr)
  416.     { return(readbutton(w, ptr, TRUE, TRUE)); }
  417.  
  418.  
  419. /*
  420.  * set icon for the application or a shell.
  421.  */
  422.  
  423. void set_icon(
  424.     Widget            shell,
  425.     int            sub)        /* 0=main, 1=submenu */
  426. {
  427. #ifndef sgi
  428.     Pixmap            icon;
  429.  
  430.     if (icon = XCreatePixmapFromBitmapData(display,
  431.                 DefaultRootWindow(display),
  432.                 (char *)(sub ? bm_icon_bits : bm_icon_bits),
  433.                 bm_icon_width, bm_icon_height,
  434.                 BlackPixelOfScreen(XtScreen(shell)),
  435.                 WhitePixelOfScreen(XtScreen(shell)),
  436.                 DefaultDepth(display, DefaultScreen(display))))
  437.  
  438.         XtVaSetValues(shell, XmNiconPixmap, icon, NULL);
  439. #endif
  440. }
  441.  
  442.  
  443. /*
  444.  * set mouse cursor to one of the predefined shapes. This is used in the
  445.  * form editor's canvas drawing area. The list of supported cursors is in
  446.  * <X11/cursorfont.h>.
  447.  */
  448.  
  449. void set_cursor(
  450.     Widget            w,        /* in which widget */
  451.     int            n)        /* which cursor, one of XC_* */
  452. {
  453.     static Cursor        cursor[XC_num_glyphs];
  454.  
  455.     if (!cursor[n])
  456.         cursor[n] = XCreateFontCursor(display, n);
  457.     XDefineCursor(display, XtWindow(w), cursor[n]);
  458. }
  459.  
  460.  
  461. /*
  462.  * truncate <string> such that it is not longer than <len> pixels when
  463.  * drawn with font <sfont>, by storing \0 somewhere in the string.
  464.  */
  465.  
  466. void truncate_string(
  467.     register char    *string,    /* string to truncate */
  468.     register int    len,        /* max len in pixels */
  469.     int        sfont)        /* font of string */
  470. {
  471.     while (*string) {
  472.         len -= font[sfont]->per_char
  473.                [*string - font[sfont]->min_char_or_byte2].width;
  474.         if (len < 0)
  475.             *string = 0;
  476.         else
  477.             string++;
  478.     }
  479. }
  480.  
  481.  
  482. /*
  483.  * return the length of <string> in pixels, when drawn with <sfont>
  484.  */
  485.  
  486. int strlen_in_pixels(
  487.     register char    *string,    /* string to truncate */
  488.     int        sfont)        /* font of string */
  489. {
  490.     register int    len = 0;    /* max len in pixels */
  491.  
  492.     while (*string) {
  493.         len += font[sfont]->per_char
  494.                [*string - font[sfont]->min_char_or_byte2].width;
  495.         string++;
  496.     }
  497.     return(len);
  498. }
  499.  
  500.  
  501. /*
  502.  * convert ascii code to and from a string representation. This is used for
  503.  * a few input buttons in the form editor window that accept single chars.
  504.  */
  505.  
  506. char *to_octal(
  507.     int        n)        /* ascii to convert to string */
  508. {
  509.     static char    buf[8];
  510.  
  511.     if (n == '\t')            return("\\t");
  512.     if (n == '\n')            return("\\n");
  513.     if (n <= 0x20 || n >= 0x7f)    { sprintf(buf, "\\%03o", n); }
  514.     else                { buf[0] = n; buf[1] = 0;    }
  515.     return(buf);
  516. }
  517.  
  518. char to_ascii(
  519.     char        *str,        /* string to convert to ascii */
  520.     int        def)        /* default if string is empty */
  521. {
  522.     int        n;
  523.     char        *p = str;
  524.  
  525.     if (!p)
  526.         return(def);
  527.     while (*p == ' ' || *p == '\t') p++;
  528.     if (!*p)
  529.         return(def);
  530.     if (*p == '\\') {
  531.         if (p[1] == 't')    return('\t');
  532.         if (p[1] == 'n')    return('\n');
  533.         if (p[1] >= '0' &&
  534.             p[1] <= '7')    { sscanf(p+1, "%o", &n); return(n); }
  535.         if (p[1] == 'x')    { sscanf(p+2, "%x", &n); return(n); }
  536.         return('\\');
  537.     } else
  538.         return(*p);
  539. }
  540.